
package com.pactera.common.redis.def;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.pactera.common.redis.RedisProperties;
import com.pactera.common.utils.StrUtils;

import redis.clients.jedis.JedisPoolConfig;

/**
 * 类名称：RedisConfig 
 * 类描述：redis 缓存管理 
 * 创建人：lee 
 * 创建时间：2016年12月7日 下午6:57:43
 * 
 * @version 1.0.0
 */
@Configuration
@EnableCaching
public class RedisDefConfig extends CachingConfigurerSupport {
	
	@Bean
    public CacheManager cacheManager(RedisTemplate redisDefTemplate) {
        RedisCacheManager rcm = new RedisCacheManager(redisDefTemplate);
        
        /*//设置缓存过期时间
        rcm.setDefaultExpiration(60);//秒
        
        //设置value的过期时间
        Map<String,Long> map = new HashMap();
        map.put("test",60L);
        rcm.setExpires(map);*/
        
        return rcm;
    }
		
	
	@SuppressWarnings("rawtypes")
	@Bean(name = "redisDefTemplate")
	public StringRedisTemplate redisTemplate(
			@Value("${spring.redis.host}") String host,
			@Value("${spring.redis.port}") int port, 
			@Value("${spring.redis.password}") String password,
			@Value("${spring.redis.database}") int database, 
			@Value("${spring.redis.timeout}") int timeout, 
			@Value("${spring.redis.pool.max-active}") int maxActive, //高版本已废弃
			@Value("${spring.redis.pool.min-idle}") int minIdle, 
			@Value("${spring.redis.pool.max-idle}") int maxIdle, 
			@Value("${spring.redis.pool.max-total}") int maxTotal,
			@Value("${spring.redis.pool.max-wait}") int maxWait,//高版本已废弃
			@Value("${spring.redis.pool.max-wait-millis}") long maxWaitMillis,
			@Value("${spring.redis.pool.test-on-borrow}") boolean testOnBorrow) {
		
		StringRedisTemplate template = new StringRedisTemplate();
		
		RedisProperties properties = new RedisProperties();
		properties.setHost(host);
		properties.setPort(port);
		properties.setPassword(password);
		properties.setDatabase(database);
		properties.setTimeout(timeout);
		properties.setMaxActive(maxActive);
		properties.setMinIdle(minIdle);
		properties.setMaxIdle(maxIdle);
		properties.setMaxTotal(maxTotal);
		properties.setMaxWait(maxWait);
		properties.setMaxWaitMillis(maxWaitMillis);
		properties.setTestOnBorrow(testOnBorrow);
		
		template.setConnectionFactory(connectionFactory(properties));
		
	    //key序列化
		RedisSerializer<String> redisSerializer = new StringRedisSerializer();//Long类型会出现异常信息;需要我们上面的自定义key生成策略，一般没必要
		
        ObjectMapper om = new ObjectMapper();  
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);  
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);  
        
      
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);  
        jackson2JsonRedisSerializer.setObjectMapper(om);  

        //key序列化
        template.setKeySerializer(redisSerializer);
        
        //value序列化
        template.setValueSerializer(jackson2JsonRedisSerializer);  
        
        //value hashmap序列化
        template.setHashValueSerializer(jackson2JsonRedisSerializer);  
        template.afterPropertiesSet();  
		
		return template;
	}

	public RedisConnectionFactory connectionFactory(RedisProperties properties) {
		JedisConnectionFactory conn = new JedisConnectionFactory();
		conn.setHostName(properties.getHost());
		conn.setPort(properties.getPort());
		if (!StrUtils.isEmpty(properties.getPassword())) {
			conn.setPassword(properties.getPassword());
		}
		conn.setDatabase(properties.getDatabase());
		conn.setTimeout(properties.getTimeout());
		conn.setPoolConfig(getPoolCofig(properties));
		conn.afterPropertiesSet();// 初始化连接pool
		return conn;
	}

	public JedisPoolConfig getPoolCofig(RedisProperties properties) {
		JedisPoolConfig poolCofig = new JedisPoolConfig();
		poolCofig.setMinIdle(properties.getMinIdle());
		poolCofig.setMaxIdle(properties.getMaxIdle());
		poolCofig.setMaxTotal(properties.getMaxTotal());
		poolCofig.setMaxWaitMillis(properties.getMaxWaitMillis());
		poolCofig.setTestOnBorrow(properties.isTestOnBorrow());
		return poolCofig;
	}
	
	/**
     * 自定义key. 这个可以不用
     * 此方法将会根据类名+方法名+所有参数的值生成唯一的一个key,即使@Cacheable中的value属性一样，key也会不一样。
     */
   /* @Override
    public KeyGenerator keyGenerator(){  
        return new KeyGenerator() {  
            @Override  
            public Object generate(Object target, Method method, Object... params) {  
                StringBuilder sb = new StringBuilder();  
                sb.append(target.getClass().getName());  
                sb.append(method.getName());  
                for (Object obj : params) {  
                    sb.append(obj.toString());  
                }  
                return sb.toString();  
            }  
        };  
    }  */
}
